package myJs.myPkg.yup

import myJs.Implicits.{FieldValue, JDS}
import slinky.readwrite.ObjectOrWritten

import scala.concurrent.Future
import scala.scalajs.js
import scala.scalajs.js.annotation.{JSImport, JSName}
import scala.scalajs.js.|



@js.native
trait RequiredStringSchema extends StringSchema {}
@js.native
trait Reference extends js.Object

@js.native
trait TContext extends js.Object {

  def parent: js.Dictionary[String] = js.native

}

@js.native
trait AnySchema extends js.Object {

  def when(keys: String, options: ObjectOrWritten[ConditionOptions]): this.type = js.native

  def nullable(): this.type = js.native

  def nullable(isNullable: Boolean): this.type = js.native

  def required(message: String): this.type = js.native

  def required(): this.type = js.native

  def test(name: String, message: String, test: js.Function1[js.Any, Boolean]): this.type = js.native

  def test(name: String, message: String, test: js.Function2[js.Any,TContext, Boolean]): this.type = js.native

  @JSName("test")
  def testF(name: String, message: String, test: js.Function1[String, js.Promise[Boolean]]): this.type =
    js.native

  @JSName("test")
  def testFT(name: String, message: String, test: js.Function2[String, TContext, js.Promise[Boolean]]): this.type =
    js.native

  def oneOf(enums: js.Array[Reference], message: String): this.type = js.native
}

@js.native
trait StringSchema extends AnySchema {

  def email(message: String): this.type = js.native

}

@js.native
trait ObjectSchema extends AnySchema {
  def shape(additions: js.Dictionary[AnySchema]): ObjectSchema = js.native

}

case class ConditionOptions(
    is: Boolean | (String => Boolean),
    `then`: AnySchema,
    otherwise: js.UndefOr[AnySchema] = js.undefined
)

@js.native
trait ArraySchema extends AnySchema {

  def min(min: Int, message: String): ArraySchema = js.native

  def min(min: Int): ArraySchema = js.native

  def of(schema: ObjectSchema | StringSchema): ArraySchema = js.native

}

@js.native
trait BooleanSchema extends AnySchema {}
@js.native
trait MixedSchema extends AnySchema {}

@js.native
trait NumberSchema extends AnySchema {

  def min(min: Int, message: String): NumberSchema = js.native

  def moreThan(more: Int, message: String): NumberSchema = js.native

  def max(max: Int, message: String): NumberSchema = js.native

  def typeError(message: String): NumberSchema = js.native

  def integer(message: String): NumberSchema = js.native

  def notRequired(): NumberSchema = js.native

  def transform(fn: js.Function1[Double, js.UndefOr[Double]]): NumberSchema = js.native

  def positive(message:String): this.type = js.native

}

@JSImport("yup", JSImport.Default)
@js.native
object Yup extends js.Object {

  type AnySchema = RequiredStringSchema | ArraySchema | NumberSchema | ObjectSchema | StringSchema | BooleanSchema

  type ObjectShape = js.Dictionary[AnySchema]

  def `object`(options: ObjectShape): ObjectSchema = js.native

  def `object`(): ObjectSchema = js.native

  def string(): StringSchema = js.native

  def number(): NumberSchema = js.native

  def array(): ArraySchema = js.native

  def boolean(): BooleanSchema = js.native

  def mixed(): MixedSchema = js.native
  def ref(key: String): Reference = js.native
}
